#ifndef COMMAND_H_
#define COMMAND_H_

#include <list>

class Document;

class Command
{
public:
	virtual ~Command(){}

protected:
	Command(){}

public:
	virtual void execute() = 0;
	virtual void undo() = 0;

	virtual Command* clone() = 0;
};

class CutCommand : public Command
{
public:
	CutCommand(Document*);
	~CutCommand(){}

public:
	void execute();
	void undo();

	Command* clone();

private:
	Document* m_pDoc;
};

template <class Receiver>
class SimpleCommand : public Command
{
public:
	typedef void (Receiver::* Action)();

public:
	SimpleCommand(Receiver* receiver, Action action, Action redo)
	{
		m_pReceiver = receiver;
		m_action = action;
		m_undo = redo;
	}

public:
	virtual void execute();
	virtual void undo();
	virtual Command* clone();

private:
	Receiver* m_pReceiver;
	Action m_action;
	Action m_undo;
};

template <class Receiver>
void SimpleCommand<Receiver>::execute()
{
	(m_pReceiver->*m_action)();
}

template <class Receiver>
void SimpleCommand<Receiver>::undo()
{
	(m_pReceiver->*m_undo)();
}

template <class Receiver>
Command* SimpleCommand<Receiver>::clone()
{
	SimpleCommand<Receiver>* pNewCmd = 
		new SimpleCommand<Receiver>(
			m_pReceiver, m_action, m_undo);
	*pNewCmd = *this;
	return pNewCmd;
}

class CommandList
{
public:
	CommandList(){}
	~CommandList();

public:
	void add(Command*);

	void undo();
	void undoAll();

	void redo();
	void redoAll();

private:
	bool checkUndo();
	bool checkRedo();

private:
	std::list<Command*> m_undoList;
	std::list<Command*> m_redoList;
};

#endif // COMMAND_H_
